#include "SGNodes.h"
#include "iRenderer.h"
#include "neiderra/core/Base.h"
#include "Mesh.h"
#include "Image.h"
#include "Texture.h"
#include "ParticleSystem.h"

#include <algorithm>
#include <vector>

using neiderra::core::iObject;
using neiderra::rendering::Mesh;
using neiderra::rendering::Image;
using neiderra::rendering::iRenderer;
using namespace neiderra::rendering::sg;
// using neiderra::scene::aSceneObject;
using neiderra::rendering::Texture;
using std::vector;

int neiderra::rendering::sg::sgNode::maxTraverseLevel = -1;
int neiderra::rendering::sg::sgNode::currentPass = 1;

// sgNode::sgNode(Scene* scene): neiderra::core::iObject()
// {
// 	_scene = scene;
// 	_parent = 0;
// 	_depthLevel = 0;
// 	_traverseLevel = 1;
// }

sgNode::sgNode()
{
// 	_scene=0; 
	_depthLevel =0; 
	_traverseLevel = 1;	// first
}

sgNode* sgNode::FindContainer(unsigned x, unsigned y)
{
	vector<sgNode*>::iterator i = _children.begin();

	sgNode* tmpc;
	sgNode* topc=0;

	int olddl = this->GetDepthLevel();
	for(; i!=_children.end(); i++ )
	{
		tmpc = (*i)->FindContainer(x, y);
		if (tmpc){
			if (tmpc->GetDepthLevel() >= olddl)
			{
				olddl = tmpc->GetDepthLevel();
				topc = tmpc;
			}
		}
	}
	return topc;
}

sgNode::~sgNode()
{
}

// void sgNode::SetScene(aScene* scene)
// {
// 	_scene = scene;
// }
// 
// void sgNode::SetSceneObject(aSceneObject* obj)
// {
// 	_sceneObject = obj;
// }
// 
// aScene* sgNode::GetScene()
// {
// 	return _scene; 
// }
// 
// aSceneObject* sgNode::GetSceneObject()
// {
// 	return _sceneObject;
// }

void sgNode::setParent(sgNode* parent)
{
	_parent = parent;
}

void sgNode::addNode(sgNode* node)
{
	node->setParent(this);
    _children.push_back(node);
}

void sgNode::removeNode(sgNode* node)
{
	vector<sgNode*>::iterator f = find(_children.begin(), _children.end(), node);
	if(f!=_children.end())
		_children.erase(f);		
}

inline bool sgNode::canPass() 
{
	if(_traverseLevel != -1 
		&& _traverseLevel != currentPass)
			return false;
	return true;
}

void sgNode::traverse(iRenderer* r)
{
	if(!canPass()) 
		return;

    std::vector<sgNode*>::iterator i = _children.begin();
    for(; i!=_children.end(); i++)
    {
		sgNode* n = (*i);
		if(n->canPass()) 
			n->traverse(r);
    }
}

// sgDOFNode::sgDOFNode(aScene* scene): sgNode(scene)
// {
// 	_traverseLevel = -1;	// always
// }

sgDOFNode::sgDOFNode(): sgNode() { _traverseLevel = -1; }// always}

sgDOFNode::~sgDOFNode()
{
}

void sgDOFNode::traverse(iRenderer* r)
{
    r->pushMatrix();

	r->render(this);
    sgNode::traverse(r);

    r->popMatrix();
}

// sgDOFRotateNode::sgDOFRotateNode(aScene* scene): sgDOFNode(scene)
// {
//     _angle =0; _x = _y = _z = 1;
// 	_rotation.identity();
// }

sgDOFRotateNode::sgDOFRotateNode(): sgDOFNode() {
	_angle =0; _x=_y=_z=0;
}

sgDOFRotateNode::~sgDOFRotateNode()
{
}

void sgDOFRotateNode::rotate(float angle, float x, float y, float z)
{
    //_angle = angle;
    //_x = x;
    //_y = y;
    //_z = z;
	_rotation.setRotateAboutAxis(vec3(x, y, z), angle);
}

void sgDOFRotateNode::rotate(quat& q)
{
	_rotation = q;
}

void sgDOFRotateNode::traverse(iRenderer* r)
{
    //r->rotatef(_angle,_x,_y,_z);
	
	r->pushMatrix();

	r->render(this);

    sgNode::traverse(r);

	r->popMatrix();
}

// sgDOFTranslateNode::sgDOFTranslateNode(aScene* scene): sgDOFNode(scene)
// {
// 	_trans.set(0.0f,0.0f,0.0f);
// }

sgDOFTranslateNode::sgDOFTranslateNode(): sgDOFNode() 
{
	_trans.set(0.0f, 0.0f, 0.0f);
}

sgDOFTranslateNode::~sgDOFTranslateNode()
{
}

sgDOFTripleNode::sgDOFTripleNode(): sgDOFTranslateNode()
{
	_rotateNode = new sgDOFRotateNode();
	_scaleNode = new sgDOFScaleNode();
	
//	this->addNode(_rotateNode);
	sgNode::addNode(_rotateNode);
	_rotateNode->addNode(_scaleNode);
}

sgDOFTripleNode::~sgDOFTripleNode()
{
}

void sgDOFTripleNode::addNode(sgNode* node)
{
	_scaleNode->addNode(node);
}

void sgDOFTranslateNode::traverse(iRenderer *r)
{
//    r->translatef(_x,_y,_z);
	r->pushMatrix();
	r->render(this);

	sgNode::traverse(r);

	r->popMatrix();
}

void sgDOFTranslateNode::translate(vec3& trans)
{
    _trans = trans;
}

// sgDOFScaleNode::sgDOFScaleNode(aScene* scene): sgDOFNode(scene)
// {
//     _x = _y = _z = 1;
// }

sgDOFScaleNode::sgDOFScaleNode(): sgDOFNode() {
	_x = _y = _z = 1;
}

sgDOFScaleNode::~sgDOFScaleNode()
{
}

void sgDOFScaleNode::traverse(iRenderer* r)
{
//    r->scalef(_x, _y, _z);
	r->pushMatrix();

	r->scalef(_x, _y, _z);
    sgNode::traverse(r);
	r->popMatrix();
}

void sgDOFScaleNode::scale(float x, float y, float z)
{
    _x = x;
    _y = y;
    _z = z;
}

/*sgGeometryNode::sgGeometryNode(aScene* scene): sgDotNode(scene)
{
    _mesh = 0;
	_texture = 0;
	_useLocalTransform = false;
}*/

sgGeometryNode::sgGeometryNode() : sgDotNode() {
	_useLocalTransform = false;
	_mesh=0;
	_texture = 0;
}

sgGeometryNode::~sgGeometryNode()
{
}

void sgGeometryNode::traverse(iRenderer* r)
{
	r->pushMatrix();
    //r->traverse(this);
	//if(_useLocalTransform)
	//	r->multMatrix(_mesh->getLocalTransform());

	if(_mesh)
		r->render(_mesh, _texture);

    sgNode::traverse(r);

	r->popMatrix();
}

void sgGeometryNode::setMesh(Mesh* mesh)
{
    _mesh = mesh;
}

void sgGeometryNode::setTexture(Texture* texture)
{
	_texture = texture;
}

Texture* sgGeometryNode::getTexture()
{
	return _texture;
}

Mesh* sgGeometryNode::getMesh()
{
    return _mesh;
}

// sgImageNode::sgImageNode(aScene* scene): sgNode(scene)
// {
//     _image = 0;
//     _x = _y = 0;
// }

sgImageNode::~sgImageNode()
{
}

void sgImageNode::traverse(iRenderer* r)
{
//	r->pushMatrix();
    //r->traverse(this);
    r->render(_image, _x, _y);
    sgNode::traverse(r);
//	r->popMatrix();
}

void sgTextNode::traverse( iRenderer* r)
{
	r->render(_str, _pen_x, _pen_y);
}

sgNode* sgImageNode::FindContainer(unsigned x, unsigned y)
{
	std::vector<sgNode*>::iterator i;

	const int width = _image->getWidth();
	const int height = _image->getHeight();
	
	// 1. determine if this node is owner
	if( (x <= _x+width) && (x >=_x) && (y <=_y+height) && (y>=_y))
	{
		
		// 2. if true, determine child container
		sgNode* tmpc=0, *cc=0; // temp containers
		unsigned tmpdl=0, dl=0;	// temp depth levels
		for(i = _children.begin(); i!=_children.end(); i++)
		{
			tmpc = (*i)->FindContainer(x, y);
			if(!tmpc) continue;

			tmpdl = tmpc->GetDepthLevel();
			if(dl<tmpdl) cc = tmpc;
		}

		if(!cc) return this;
		else return cc;

	}
	else {
		return 0;
	}
}


void sgImageNode::setImage(Image* img)
{
    _image = img;
}

void sgImageNode::setXY(int x, int y)
{
    _x = x;
    _y = y;
}

Image* sgImageNode::getImage()
{
    return _image;
}

// CAMERA NODE IMPLEMENTATION

// sgCameraNode::sgCameraNode(aScene* scene): sgDotNode(scene)
// {
// 	_dest = 0;
// }

sgCameraNode::~sgCameraNode() 
{
}

void sgCameraNode::setDestinationNode(sgDotNode* sdn)
{
	_dest = sdn;
}

sgDotNode* sgCameraNode::getDestinationNode() {return _dest;}

void sgCameraNode::traverse(iRenderer* r)
{
	// not implemented yet 
}

// END - CAMERA NODE IMPLEMENTATION

// sgDOFOrientNode::sgDOFOrientNode(aScene* scene): sgDOFNode(scene)
// {
// 	//default
// 	_view = _pos = _up = 0;
// 	_view.z = -1.0f;
// 	_up.y = 1.0f;
// }

sgDOFOrientNode::sgDOFOrientNode(): sgDOFNode()
{
	//default
	_view = _pos = _up = 0;
	_view.z = -1.0f;
	_up.y = 1.0f;
}

void sgDOFOrientNode::traverse(iRenderer* r)
{
//	r->tra
}

// sgStringNode::sgStringNode(aScene* scene): sg2dNode(scene)
// {
// 	_s="";
//     _alphabet = 0;
// }

void sgStringNode::traverse(iRenderer* r)
{
	r->pushMatrix();

	r->render(this);
	sgNode::traverse(r);

	r->popMatrix();
}

sgStringNode::~sgStringNode()
{
}

// sgParticleSystemNode::sgParticleSystemNode(aScene* scene): sgNode(scene)
// {
// 	_traverseLevel = 2;
// }

sgParticleSystemNode::sgParticleSystemNode() : sgNode()
{
	_traverseLevel = 2;
}

void sgParticleSystemNode::traverse(iRenderer* r)
{
	if(_particleSystem)
		_particleSystem->render(r);
}
